package com.zhanghu.backendZray.config.mvc;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.InjectableValues;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.zhanghu.backendZray.config.filter.XSSMappingJackson2HttpMessageConverter;
import com.zhanghu.backendZray.interceptor.AsyncHelloInterceptor;
import com.zhanghu.backendZray.serializer.LocalDateTimeJacksonDeserializer;
import com.zhanghu.backendZray.serializer.LocalDateTimeJacksonSerializer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.List;


/**
 * @author ZhangDong
 * @date 2023/7/11 11:18
 */
@Configuration
@Slf4j
public class MvcConfig implements WebMvcConfigurer {
    /**
     * 不需要拦截的请求路径
     */
    public static final String[] xUrls = {"/login", "/logout"};
    @Resource
    private AsyncHelloInterceptor asyncHelloInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(asyncHelloInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns(xUrls);
    }

    /**
     * 自定义线程池处理
     *
     * @param configurer
     */
    @Override
    public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        // 核心线程数
        threadPoolTaskExecutor.setCorePoolSize(2);
        threadPoolTaskExecutor.setAllowCoreThreadTimeOut(true);
        // 最大线程数
        threadPoolTaskExecutor.setMaxPoolSize(4);
        // 配置队列大小
        threadPoolTaskExecutor.setQueueCapacity(100);
        // 配置线程池前缀
        threadPoolTaskExecutor.setThreadNamePrefix("async-service-thread");
        threadPoolTaskExecutor.initialize();

        configurer.setTaskExecutor(threadPoolTaskExecutor);
        /*
         * AsyncRequestTimeoutException 通常发生在异步请求超时的情况下。Spring 的默认超时时间可能不够长，导致超时抛出异常。这可能由以下原因导致：
         *  如果你的 TongyiUtil.call() 方法或后续处理时间过长，超过了 Spring MVC 默认的异步请求超时时间（通常是 30 秒），就会引发该异常。
         *
         */
        // 60 seconds
        configurer.setDefaultTimeout(60000);
    }

    /**
     * 将springboot默认的jackson改为fastjson
     */
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        /*FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
        // 添加fastJson的配置信息
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect,
                SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullStringAsEmpty);
        // 去你的，这种只对Date类型有用，对LocalDateTime没用
        fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");
        // 将LocalDateTime类与自定义序列化器关联
        fastJsonConfig.getSerializeConfig().put(LocalDateTime.class, new LocalDateTimeSerializer());
        // 处理中文乱码问题
        List<MediaType> fastMediaTypes = new ArrayList();
        fastMediaTypes.add(MediaType.APPLICATION_JSON);
        fastMediaTypes.add(MediaType.TEXT_EVENT_STREAM);
        fastConverter.setSupportedMediaTypes(fastMediaTypes);
        fastConverter.setFastJsonConfig(fastJsonConfig);
        fastConverter.setDefaultCharset(Charset.forName("UTF-8"));
        converters.add(0, fastConverter);*/

        /**
         * jackson配置日期格式
         */
//        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        XSSMappingJackson2HttpMessageConverter converter = new XSSMappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = converter.getObjectMapper();
        // 生成JSON时,将所有Long转换成String
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        simpleModule.addSerializer(LocalDateTime.class, new LocalDateTimeJacksonSerializer());
        simpleModule.addDeserializer(LocalDateTime.class, new LocalDateTimeJacksonDeserializer());
        objectMapper.registerModule(simpleModule);
        // 时间格式化
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 这种只对Date类型和LocalDate有用
        // 对LocalDate有用是出乎意料的，会格式化成这种：yyyy-MM-dd
        // 如果不设置下面这个，输出的localDate是个集合，eg：[2024, 6, 14】
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        InjectableValues.Std iv = new InjectableValues.Std();
        iv.addValue(LocalDateTime.class, LocalDateTime.now());
        objectMapper.setInjectableValues(iv);
        // 设置格式化内容
        converter.setObjectMapper(objectMapper);
        converters.add(0, converter);
    }

    @Bean
    public ThreadPoolTaskExecutor executor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(2);
        taskExecutor.setMaxPoolSize(10);
        taskExecutor.setQueueCapacity(50);
        taskExecutor.setThreadNamePrefix("huang");// 异步任务线程名以 huang 为前缀
        return taskExecutor;
    }
}


